package us.luosl.lslt.collection;

import us.luosl.lslt.function.stream.StreamWrapper;

import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public abstract class AbstractIterator<T> implements Iterator<T> {

    public static final AbstractIterator<Object> emptyIterator = new AbstractIterator<Object>() {
        @Override
        public boolean hasNext() {
            return false;
        }

        @Override
        protected Object getNext() {
            throw new NoSuchElementException("next() on empty iterator");
        }
    };

    protected abstract T getNext();

    @Override
    public final T next() {
        if (!hasNext()) {
            throw new NoSuchElementException("next() on empty iterator");
        }
        return getNext();
    }

    public boolean isEmpty(){
        return !hasNext();
    }

    public Stream<T> stream(){
        return StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(this, Spliterator.ORDERED),
                false
        );
    }

    public StreamWrapper<T> streamWrapper(){
        return StreamWrapper.wrap(stream());
    }

    @SuppressWarnings("unchecked")
    public static <T> AbstractIterator<T> empty() {
        return (AbstractIterator<T>) emptyIterator;
    }

    public static <T> Iterator<T> of(T element) {
        return new AbstractIterator<T>() {

            boolean hasNext = true;

            @Override
            public boolean hasNext() {
                return hasNext;
            }

            @Override
            public T getNext() {
                hasNext = false;
                return element;
            }
        };
    }

    public static <T> AbstractIterator<T> create(Iterator<T> itr){
        return new AbstractIterator<T>() {
            @Override
            public boolean hasNext() {
                return itr.hasNext();
            }

            @Override
            protected T getNext() {
                return itr.next();
            }
        };
    }

}